//
//  CSprite.cpp
//  NinjaTurtle
//
//  Created by Nguyen Tri Chung on 1/6/15.
//
//

#include "CSprite.h"

CSprite::CSprite(string spriteType) {
    this->retainedActions = new Map<string, Action*>();
    this->spriteType = spriteType;
    this->runningAction = NULL;
    this->oOVector = Point::ZERO;
    this->lastActionName = "";
    this->autorelease();
}

CSprite::~CSprite() {
    CC_SAFE_DELETE(this->retainedActions);
}

bool CSprite::init() {
    bool ret = Sprite::init();
    this->getTexture()->setAliasTexParameters();
    return ret;
}

bool CSprite::initWithFile(const string& filename) {
    bool ret = Sprite::initWithFile(filename);
    this->getTexture()->setAliasTexParameters();
    return ret;
}

bool CSprite::initWithSpriteFrameName(const string& spriteFrameName) {
    bool ret = Sprite::initWithSpriteFrameName(spriteFrameName);
    this->getTexture()->setAliasTexParameters();
    return ret;
}

void CSprite::initWithIdentifier(const string& identifier) {
    string frameName = identifier + BIND_CONSTANT_SUFFIX;
    if (!initWithSpriteFrameName(frameName)) {
        assert(NULL);
    }
}

Action* CSprite::createFrameCaheAction(const string& pattern, int count, float duration, bool loop) {
    SpriteFrameCache* spriteFrameCache = SpriteFrameCache::getInstance();
    Vector<SpriteFrame*>* framesVector = new Vector<SpriteFrame*>;
    char frameName[128];
    for(int i = 1; i <= count; i++){
        sprintf(frameName, pattern.c_str(), i);
        SpriteFrame* frame = spriteFrameCache->getSpriteFrameByName(frameName);
        framesVector->pushBack(frame);
    }

    float delay = duration / framesVector->size();
    Animation* animation = Animation::createWithSpriteFrames(*framesVector, delay);
    Animate* animate = Animate::create(animation);
    Action* action = NULL;
    if (loop) {
        action = RepeatForever::create(animate);
    } else {
        action = (Action*) animate;
    }
    delete framesVector;
    return action;
}

void CSprite::retainAction(Action* actionValue, const string& actionKey) {
    if (this->retainedActions->at(actionKey) != NULL) {
        assert(NULL);
    }
    this->retainedActions->insert(actionKey, actionValue);
}

void CSprite::bind(const string& pattern, float duration) {
    vector<string> values = CStringUtil::split(pattern, BIND_DELIMITER);
    if (values.size() != 2) {
        assert(NULL);
    }
    
    string plistFile = values[0];
    string identifier = values[1];
    
    ValueMap* dict = SpecialResource::getInstance()->getInfoPlist();
    ValueMap frames = dict->at(BIND_PLIST_FRAMES_NODE).asValueMap();
    int foundTotal = 0;
    
    for (auto& frame : frames) {
        string prefix = frame.first.substr(0, frame.first.find_last_of(BIND_PATTERN_CONNECTOR));
        if (prefix == identifier) {
            foundTotal++;
        }
    }
    
    if (foundTotal == 0) {
        assert(NULL);
    }
    
    if (duration == -1) {
        duration = BIND_DEFAULT_DURATION_PER_FRAME * foundTotal;
    }
    
    string frameNamePattern = identifier + BIND_PATTERN_SUFFIX;
    string nameNotLoop = identifier + BIND_NOT_LOOP;
    string nameLoop = identifier + BIND_LOOP;
    
    Action* notLoopAction = createFrameCaheAction(frameNamePattern, foundTotal, duration, false);
    retainAction(notLoopAction, nameNotLoop);
    
    Action* loopAction = createFrameCaheAction(frameNamePattern, foundTotal, duration, true);
    retainAction(loopAction, nameLoop);
    
    this->lastActionName = identifier;
}

void CSprite::playLastAction(bool loop) {
    if (this->lastActionName == "") {
        assert(NULL);
    }
    
    if (loop) {
        this->playLoop(this->lastActionName);
    } else {
        this->play(this->lastActionName);
    }
}

void CSprite::resetAction(const string& pattern, bool loop, Action* newAction) {
    string actionName;
    if (loop) {
        actionName = pattern + BIND_LOOP;
    } else {
        actionName = pattern + BIND_NOT_LOOP;
    }
    this->retainedActions->insert(actionName, newAction);
}

Action* CSprite::getAction(const string& pattern, bool loop) {
    string actionName;
    if (loop) {
        actionName = pattern + BIND_LOOP;
    } else {
        actionName = pattern + BIND_NOT_LOOP;
    }
    Action* selectedAction = this->retainedActions->at(actionName);
    return selectedAction;
}

Action* CSprite::getActionExactly(const string& key) {
    Action* selectedAction = this->retainedActions->at(key);
    return selectedAction;
}

void CSprite::play(const string& action) {
    string nameNotLoop = action + BIND_NOT_LOOP;
    Action* selectedAction = this->retainedActions->at(nameNotLoop);
    
    if (this->runningAction != selectedAction) {
        if (this->runningAction != NULL) {
            stopAction(this->runningAction);
        }
        if (selectedAction != NULL) {
            this->runningAction = selectedAction;
            runAction(this->runningAction);
        } else {
            this->runningAction = NULL;
        }
    }
}

void CSprite::playLoop(const string& action) {
    string nameLoop = action + BIND_LOOP;
    Action* selectedAction = this->retainedActions->at(nameLoop);
    
    if (this->runningAction != selectedAction) {
        if (this->runningAction != NULL) {
            stopAction(this->runningAction);
        }
        if (selectedAction != NULL) {
            this->runningAction = selectedAction;
            runAction(this->runningAction);
        } else {
            this->runningAction = NULL;
        }
    }
}